Pular para o conteúdo principal

Configuração do microservice em Node

Na pasta src/config, temos os arquivos de configuração do microservice em Node.

O arquivo src/config/configuration.ts define o esquema zod de uma configuração válida para o microservice em Node.

Exemplo de arquivo de configuração:

import { z } from 'zod';
import {
Environment,
getEnvironment,
NodeType,
safeInstantiateEntity,
} from '../utils';
import { createZodDto } from 'nestjs-zod';
import localConfiguration from './local.configuration';
import integrationTestConfiguration from './integration-test.configuration';
import developmentConfiguration from './development.configuration';

export const configKey = 'config';

export const ConfigurationSchema = z.object({
nodeEnv: z.nativeEnum(Environment),
nodeType: z.nativeEnum(NodeType),
databaseUrl: z.string(),
email: z.object({
from: z.string().email(),
}),
sendgrid: z.object({
apiKey: z.string(),
}),
twillio: z.object({
accountSid: z.string(),
authToken: z.string(),
phoneNumber: z.string(),
}),
jwt: z.object({
accessSecret: z.string(),
refreshSecret: z.string(),
}),
app: z.object({
url: z.string().url(),
}),
pluggy: z.object({
clientId: z.string(),
clientSecret: z.string(),
webhookHeaderKey: z.string(),
}),
google: z.object({
project: z.enum([
'null',
'sofia-development-cceeb',
'sofia-app-staging',
'sofia-app-production',
]),
location: z.literal('southamerica-east1'),
}),
worker: z.object({
io: z.object({
url: z.string().url(),
headerKey: z.string(),
}),
cpu: z.object({
url: z.string().url(),
headerKey: z.string(),
}),
}),
logger: z.object({
level: z.enum(['info', 'debug']),
betterStackSourceToken: z.string(),
}),
});

export class ConfigurationEntity extends createZodDto(ConfigurationSchema) {
static build(
input: z.infer<typeof ConfigurationSchema>,
): ConfigurationEntity {
return safeInstantiateEntity(ConfigurationEntity, input);
}
}

export function loadConfiguration() {
const environment = getEnvironment();
switch (environment) {
case Environment.LOCAL:
return localConfiguration;
case Environment.INTEGRATION_TEST:
return integrationTestConfiguration;
case Environment.DEVELOPMENT:
return developmentConfiguration;
default:
throw new Error(`Unsupported environment: ${environment}.`);
}
}

Para cada ambiente, o arquivo de configuração correspondente é carregado.

Exemplo de arquivo de configuração para o ambiente de desenvolvimento (src/config/development.configuration.ts):

import { Environment, NodeType } from '../utils';
import { configKey, ConfigurationEntity } from './configuration';

/* v8 ignore start */
export default () => {
return {
[configKey]: ConfigurationEntity.build({
nodeEnv: Environment.DEVELOPMENT,
nodeType: process.env.NODE_TYPE as NodeType,
databaseUrl: process.env.DATABASE_URL!,
email: {
from: 'no-reply-dev@em3322.mailing.usesofia.com',
},
sendgrid: {
apiKey: process.env.SENDGRID_API_KEY!,
},
twillio: {
accountSid: 'ACe32e2abe25482906dc5843bd3b5d0b1b',
authToken: process.env.TWILIO_AUTH_TOKEN!,
phoneNumber: '+19785416928',
},
jwt: {
accessSecret:
'4H3Mckg2iT5lmg2VPpM3HsOMOMYOtMHeyfqXzLtBSbTOOdCcrNhuqOCuVIhOjsN6xBCUIG2ZU28weDreTX6tJWuoFr1pEr8WrBr9OcHLLE8IdABSDqLWvJNSRlFu2c5BG39rmkIrL',
refreshSecret:
'eBAF8CakeWJqReBg4v64dfjy5aKKD7OE5LeNcMML9D7ufnX5i09xrgTtPcqh4TBppCplnyf2EmhCQJ02EsxknuDaZEU3R/6tAQ/YY5G85n2G/fEzzollTMUrPH24nbj8fT6GcszxVQY8lJm9GuL1hzd/MJ9d3anfcfdiqspOJdJ8Sh36uUDA0e6EhzDrRl/wTBgJtoBVUUqakRh21nT0vzna5CWS3en9+1cvQizYYR0b/UQxdhiEqlKsYzwdAvHPvaOykYmXx4hfsDyi0prNFsGU0lR5NChtkpO6oJa9IgqXglt3lfo9J72a55kw==',
},
app: {
url: 'http://dev.app.usesofia.com',
},
pluggy: {
clientId: '3c6b20f7-e00d-4d7c-ae96-bc06f40bea18',
clientSecret: process.env.PLUGGY_CLIENT_SECRET!,
webhookHeaderKey: '123456',
},
google: {
project: 'sofia-development-cceeb',
location: 'southamerica-east1',
},
worker: {
io: {
url: 'http://dev.core-api-worker-io.usesofia.com',
headerKey: '123456',
},
cpu: {
url: 'http://dev.core-api-worker-cpu.usesofia.com',
headerKey: '123456',
},
},
logger: {
level: 'debug',
betterStackSourceToken: process.env.BETTER_STACK_SOURCE_TOKEN!,
},
}),
};
};
/* v8 ignore stop */

Para acessar a configuração em um provider ou service, basta injetar o ConfigurationService e acessar a propriedade config:

Exemplo:

import {
Inject,
Injectable,
LoggerService,
NotFoundException,
} from '@nestjs/common';
import { LoggerServiceKey } from '../logger/logger.module';
import { ClsService } from 'nestjs-cls';
import { BaseService } from '../base.service';
import { PluggyWebhookCallProvider } from './pluggy-webhook-call.provider';
import { QueueProvider } from '../queue/queue.provider';
import { BankProvider, QueueTaskHandlerType } from '@prisma/client';
import { PluggyConnectTokenEntity } from './entities/pluggy-connect-token.entity';
import { UserEntity } from '../iam/users/entities/user.entity';
import { CreatePluggyConnectTokenRequestEntity } from './entities/create-pluggy-connect-token-request.entity';
import { WorkspacesProvider } from '../iam/workspaces/workspaces.provider';
import { configKey, ConfigurationEntity } from '../config/configuration';
import { ConfigService } from '@nestjs/config';
import { PluggyClient } from 'pluggy-sdk';
import { Queue } from '../queue/queue.enums';
import { SyncBankItemRequestDto } from '../bank/bank-sync/dtos/sync-bank-item-request.dto';

@Injectable()
export class PluggyService extends BaseService {
private pluggyClient: PluggyClient;

constructor(
protected readonly clsService: ClsService,
@Inject(LoggerServiceKey)
protected readonly loggerService: LoggerService,
@Inject(PluggyWebhookCallProvider)
private readonly pluggyWebhookCallProvider: PluggyWebhookCallProvider,
@Inject(QueueProvider)
private readonly queueProvider: QueueProvider,
@Inject(WorkspacesProvider)
private readonly workspacesProvider: WorkspacesProvider,
private readonly configService: ConfigService,
) {
super(PluggyService.name, clsService, loggerService);
const config = configService.get<ConfigurationEntity>(configKey)!;
this.pluggyClient = new PluggyClient({
clientId: config.pluggy.clientId!,
clientSecret: config.pluggy.clientSecret!,
});
}
}